package com.chenl.provider.DEMOS.Spring.Spel;

import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;

/**
 * 防重提交,redis版本
 */
@Aspect
@Configuration
@Slf4j
public class SpelAspect {
    @Autowired
    BeanFactory beanFactory;

    private static final ParameterNameDiscoverer NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
    private static final ExpressionParser PARSER = new SpelExpressionParser();



    @Before("@annotation(com.chenl.provider.DEMOS.Spring.Spel.SpelAnno)")
    public void interceptor(JoinPoint joinPoint){
        String result = this.getSpelByJoinpoint(joinPoint);
        System.out.println("666"+result);
    }

    @Before("@annotation(com.chenl.provider.DEMOS.Spring.Spel.SpelServiceAnno)")
    public void interceptor2(JoinPoint joinPoint){
        String result = this.getSpelByJoinpoint2(joinPoint);
        System.out.println("777"+result);
    }


    private String getSpelByJoinpoint(JoinPoint joinPoint){
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        SpelAnno spelAnno = method.getAnnotation(SpelAnno.class);
        Object[] args = joinPoint.getArgs();
        SpelExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();
        Parameter[] parameters = method.getParameters();
        for(int i = 0; i < parameters.length; i++){
            context.setVariable(parameters[i].getName(), args[i]);
        }
        String s = JSONObject.toJSONString(parser.parseExpression(spelAnno.key()).getValue(context));
        return s;
    }

    private String getSpelByJoinpoint2(JoinPoint point){
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        SpelServiceAnno spelAnno = method.getAnnotation(SpelServiceAnno.class);
        //拼接解析springEl表达式的map
        String[] paramNames = signature.getParameterNames();
        Object[] args = point.getArgs();
        TreeMap<String, Object> treeMap = new TreeMap<>();
        for (int i = 0; i < paramNames.length; i++) {
            treeMap.put(paramNames[i],args[i]);
        }
        //创建表达式解析器
        ExpressionParser parser = new SpelExpressionParser();
        //通过evaluationContext.setVariable可以在上下文中设定变量。
        EvaluationContext context = new StandardEvaluationContext();
        treeMap.entrySet().forEach(entry->
                context.setVariable(entry.getKey(),entry.getValue())
        );

        String s = JSONObject.toJSONString(parser.parseExpression(spelAnno.key()).getValue(context));
        return s;
    }

    /**
     * 用于SpringMvc 控制层获取参数使用
     * @param keyExpress
     * @param method
     * @param args
     * @return
     */
    private String getKey(String keyExpress, Method method, Object[] args){
//        return JSONObject.toJSONString(args);
        SpelExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();
        Parameter[] parameters = method.getParameters();
        for(int i = 0; i < parameters.length; i++){
            context.setVariable(parameters[i].getName(), args[i]);
        }
        String value = (String) parser.parseExpression(keyExpress).getValue(context);
        return JSONObject.toJSONString(parser.parseExpression(keyExpress).getValue(context));
    }

    protected String getKeys(String[] definitionKeys, Method method, Object[] parameterValues) {
         BeanResolver beanResolver= new BeanFactoryResolver(beanFactory);;
        StandardEvaluationContext context = new MethodBasedEvaluationContext((Object)null, method, parameterValues, NAME_DISCOVERER);
        context.setBeanResolver(beanResolver);
        List<Object> definitionKeyList = new ArrayList(definitionKeys.length);
        String[] var6 = definitionKeys;
        int var7 = definitionKeys.length;

        for(int var8 = 0; var8 < var7; ++var8) {
            String definitionKey = var6[var8];
            if (definitionKey != null && !definitionKey.isEmpty()) {
                Object key = PARSER.parseExpression(definitionKey).getValue(context, Object.class);
                definitionKeyList.add(key);
            }
        }

        return org.springframework.util.StringUtils.collectionToDelimitedString(definitionKeyList, ".", "", "");
    }
}